package com.onLineCar.manages.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.onLineCar.manages.mapper.VehicleInfoMapper;
import com.onLineCar.manages.pojo.*;
import com.onLineCar.manages.pojo.dto.VehicleBaseInfoDTO;
import com.onLineCar.manages.pojo.dto.vehicleinfo.VehicleDocumentPhotosBean;
import com.onLineCar.manages.pojo.imageenum.ImageEnum;
import com.onLineCar.manages.pojo.request.VehicleInfoRequest;
import com.onLineCar.manages.pojo.response.CarBaseInfoResponse;
import com.onLineCar.manages.rpc.DriverMangesRPC;
import com.onLineCar.manages.rpc.dto.DriverInfoDTO;
import com.onLineCar.manages.service.*;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 车辆基本信息表 服务实现类
 * </p>
 *
 * @author zhucaiyi
 * @since 2023-12-10
 */
@Service
public class VehicleInfoServiceImpl extends ServiceImpl<VehicleInfoMapper, VehicleInfo> implements VehicleInfoService {

    @Resource
    private RideHailingCarInfoService rideHailingCarInfoService;

    @Resource
    private VehicleLevelService vehicleLevelService;

    @Resource
    private CarModelService carModelService;

    @Resource
    private BaseService baseService;

    @Resource
    private ImageTableService imageTableService;

    @Resource
    private DriverMangesRPC driverMangesRPC;

    @Override
    public IPage<VehicleInfo> queryVehicleInfo(VehicleInfoRequest vehicleInfoRequest) {
        LambdaQueryWrapper<VehicleInfo> queryWrapper = new LambdaQueryWrapper<>();
        Page<VehicleInfo> infoPage = this.page(new Page<VehicleInfo>(vehicleInfoRequest.getPageNum(), vehicleInfoRequest.getPageSize()), queryWrapper);
        List<Integer> vehicleIds = infoPage.getRecords().stream()
                .map(VehicleInfo::getVehicleId).toList();
        if (vehicleIds.isEmpty()) {
            return infoPage;
        }
        List<VehicleInfo> vehicleInfoList = infoPage.getRecords();
        LambdaQueryWrapper<RideHailingCarInfo> rideHailingCarInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        rideHailingCarInfoLambdaQueryWrapper.in(RideHailingCarInfo::getVehicleId, vehicleIds);
        Map<Integer, String> vehicleIdAndVehicleMapper = rideHailingCarInfoService.list(rideHailingCarInfoLambdaQueryWrapper)
                .stream()
                .collect(Collectors.toMap(RideHailingCarInfo::getVehicleId, RideHailingCarInfo::getColor));

        List<Long> vehicleLevelIds = vehicleInfoList.stream()
                .map(VehicleInfo::getVehicleLevelId).toList();

        LambdaQueryWrapper<VehicleLevel> vehicleLevelLambdaQueryWrapper = new LambdaQueryWrapper<>();
        vehicleLevelLambdaQueryWrapper.in(VehicleLevel::getLevelId, vehicleLevelIds);
        Map<Integer, String> vehicleLevelIdAndLevelNameMapper = vehicleLevelService.list(vehicleLevelLambdaQueryWrapper).stream()
                .collect(Collectors.toMap(VehicleLevel::getLevelId, VehicleLevel::getLevelName));

        List<Long> vehicleModelIds = vehicleInfoList.stream()
                .map(VehicleInfo::getVehicleTypeId).toList();

        LambdaQueryWrapper<CarModel> carModelLambdaQueryWrapper = new LambdaQueryWrapper<>();
        carModelLambdaQueryWrapper.in(CarModel::getId, vehicleModelIds);
        Map<Integer, String> carModelIdAndCarModelDescriptionMapper = carModelService.list(carModelLambdaQueryWrapper)
                .stream()
                .collect(Collectors.toMap(CarModel::getId, CarModel::getDescription));

        List<Integer> cityIds = vehicleInfoList
                .stream()
                .map(VehicleInfo::getCityId).toList();

        LambdaQueryWrapper<China> chinaLambdaQueryWrapper = new LambdaQueryWrapper<>();
        chinaLambdaQueryWrapper.in(China::getId, cityIds);
        Map<Integer, String> cityIdAndCityNameMapper = baseService.list(chinaLambdaQueryWrapper).stream()
                .collect(Collectors.toMap(China::getId, China::getName));

        List<Integer> vehicleIdList = vehicleInfoList.stream()
                .map(VehicleInfo::getVehicleId).toList();

        List<DriverInfoDTO> driverInfoDTOS = driverMangesRPC.selectDriverByCarId(vehicleIdList);

        Map<Integer, DriverInfoDTO> vehicleIdAndDriverInfoMapper = driverInfoDTOS.stream()
                .collect(Collectors.toMap(DriverInfoDTO::getCarId, Function.identity()));
        List<VehicleInfo> infoList = vehicleInfoList.stream()
                .map(info -> {
                    VehicleInfo vehicleInfo = new VehicleInfo();
                    CarBaseInfoResponse carBaseInfoResponse = CarBaseInfoResponse.builder()
                            .addTime(info.getCreatedAt())
                            .carId(info.getVehicleId().toString())
                            .batteryRemainingMileage("100")
                            .carColor(vehicleIdAndVehicleMapper.get(info.getVehicleId()))
                            .carLevel(vehicleLevelIdAndLevelNameMapper.get(Integer.parseInt(info.getVehicleLevelId().toString())))
                            .carModelDescription(carModelIdAndCarModelDescriptionMapper.get(Integer.parseInt(info.getVehicleTypeId().toString())))
                            .carStatus(info.getVehicleStatus())
                            .city(cityIdAndCityNameMapper.get(info.getCityId()))
                            .plateNumber(info.getLicensePlate())
                            .totalMileage("100")
                            .build();
                    DriverInfoDTO driverInfoDTO = vehicleIdAndDriverInfoMapper.get(info.getVehicleId());
                    if (ObjectUtils.isNotEmpty(driverInfoDTO)) {
                        if (driverInfoDTO.getFlag()) {
                            carBaseInfoResponse.setDriverName(driverInfoDTO.getDriverName());
                            carBaseInfoResponse.setDriverPhoneNumber(driverInfoDTO.getDriverPhone());
                            carBaseInfoResponse.setIsDriverBound(NumberUtils.INTEGER_ZERO);
                        } else {
                            carBaseInfoResponse.setIsDriverBound(NumberUtils.INTEGER_ONE);
                        }
                    }
                    return vehicleInfo.setCarBaseInfoResponse(carBaseInfoResponse);
                }).toList();
        return infoPage.setRecords(infoList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addVehicleInfo(VehicleBaseInfoDTO vehicleBaseInfoDTO) {
        VehicleInfo vehicleInfo = vehicleBaseInfoDTO.convertVehicleInfo(vehicleBaseInfoDTO.getVehicleInfoDTO());
        this.save(vehicleInfo);
        Integer vehicleId = vehicleInfo.getVehicleId();
        vehicleBaseInfoDTO.getRideHailingCarInfoDTO().setVehicleId(vehicleId);
        RideHailingCarInfo rideHailingCarInfo = vehicleBaseInfoDTO.convertRideHailingCarInfo(vehicleBaseInfoDTO.getRideHailingCarInfoDTO());
        rideHailingCarInfoService.save(rideHailingCarInfo);
        buildVehicleDocumentPhotoList(vehicleBaseInfoDTO.getVehicleDocumentPhotos(), vehicleId);
        return true;
    }

    @Override
    public VehicleBaseInfoDTO queryVehicleInfoByVehicleId(Integer vehicleId) {
        VehicleBaseInfoDTO vehicleBaseInfoDTO = new VehicleBaseInfoDTO();
        VehicleInfo vehicleInfo = this.getById(vehicleId);
        LambdaQueryWrapper<RideHailingCarInfo> rideHailingCarInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        rideHailingCarInfoLambdaQueryWrapper.eq(RideHailingCarInfo::getVehicleId, vehicleId);
        RideHailingCarInfo rideHailingCarInfo = rideHailingCarInfoService.getOne(rideHailingCarInfoLambdaQueryWrapper);
        List<ImageTable> imageTables = imageTableService.queryImageTableByBusinessId(vehicleId);
        vehicleBaseInfoDTO.setVehicleDocumentPhotos(vehicleBaseInfoDTO.convertVehicleDocumentPhotosBean(imageTables));
        vehicleBaseInfoDTO.setRideHailingCarInfoDTO(vehicleBaseInfoDTO.convertRideHailingCarInfoDTOBean(rideHailingCarInfo));
        vehicleBaseInfoDTO.setVehicleInfoDTO(vehicleBaseInfoDTO.convertVehicleInfoDTO(vehicleInfo));
        return vehicleBaseInfoDTO;
    }

    @Override
    public Boolean updateVehicleInfo(VehicleBaseInfoDTO vehicleBaseInfoDTO) {
        Integer vehicleId = vehicleBaseInfoDTO.getRideHailingCarInfoDTO().getVehicleId();
        this.updateById(vehicleBaseInfoDTO.convertVehicleInfo(vehicleBaseInfoDTO.getVehicleInfoDTO())
                .setVehicleId(vehicleId));
        LambdaQueryWrapper<RideHailingCarInfo> rideHailingCarInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        rideHailingCarInfoLambdaQueryWrapper.eq(RideHailingCarInfo::getVehicleId, vehicleId);
        rideHailingCarInfoService.update(vehicleBaseInfoDTO
                .convertRideHailingCarInfo(vehicleBaseInfoDTO.getRideHailingCarInfoDTO()), rideHailingCarInfoLambdaQueryWrapper);
        imageTableService.deleteImagesByBusinessId(vehicleId);
        buildVehicleDocumentPhotoList(vehicleBaseInfoDTO.getVehicleDocumentPhotos(), vehicleId);
        return true;
    }

    @Override
    public Boolean deleteVehicleById(Integer id) {
        this.removeById(id);
        rideHailingCarInfoService.remove(new LambdaQueryWrapper<RideHailingCarInfo>().eq(RideHailingCarInfo::getVehicleId, id));
        imageTableService.remove(new LambdaQueryWrapper<ImageTable>().eq(ImageTable::getBusinessId, id));
        return true;
    }

    private void buildVehicleDocumentPhotoList(VehicleDocumentPhotosBean vehicleDocumentPhotos, Integer vehicleId) {
        ImageTable licensePlatePhoto = vehicleDocumentPhotos(vehicleDocumentPhotos.getLicensePlatePhoto(), vehicleId, ImageEnum.CAR_LICENSE_PLATE_PHOTO);
        ImageTable drivingLicensePhoto = vehicleDocumentPhotos(vehicleDocumentPhotos.getDrivingLicensePhoto(), vehicleId, ImageEnum.CAR_DRIVING_LICENSE_PHOTO);
        ImageTable InvoicePhoto = vehicleDocumentPhotos(vehicleDocumentPhotos.getInvoicePhoto(), vehicleId, ImageEnum.CAR_INVOICE_PHOTO);
        ImageTable taxCertificatePhoto = vehicleDocumentPhotos(vehicleDocumentPhotos.getTaxCertificatePhoto(), vehicleId, ImageEnum.CAR_TAX_CERTIFICATE_PHOTO);
        ImageTable registrationCertificatePhoto = vehicleDocumentPhotos(vehicleDocumentPhotos.getRegistrationCertificatePhoto(), vehicleId, ImageEnum.CAR_REGISTRATION_CERTIFICATE_PHOTO);
        ImageTable TransportCertificatePhoto = vehicleDocumentPhotos(vehicleDocumentPhotos.getTransportCertificatePhoto(), vehicleId, ImageEnum.CAR_TRANSPORT_CERTIFICATE_PHOTO);
        ImageTable otherOnePhoto = vehicleDocumentPhotos(vehicleDocumentPhotos.getOther1Photo(), vehicleId, ImageEnum.CAR_OTHER_PHOTO);
        ImageTable OtherTwoPhoto = vehicleDocumentPhotos(vehicleDocumentPhotos.getOther2Photo(), vehicleId, ImageEnum.CAR_OTHER_PHOTO);
        List<ImageTable> imageTables = Lists.newArrayList(licensePlatePhoto, drivingLicensePhoto, InvoicePhoto,
                taxCertificatePhoto, registrationCertificatePhoto, TransportCertificatePhoto, otherOnePhoto, OtherTwoPhoto).stream().filter(Objects::nonNull).toList();
        if (CollectionUtil.isNotEmpty(imageTables)) {
            imageTableService.saveBatch(imageTables);
        }
    }

    private ImageTable vehicleDocumentPhotos(String imageUrl, Integer vehicleId, ImageEnum imageEnum) {
        if (StringUtils.isBlank(imageUrl) || vehicleId == null) {
            return null;
        }
        return ImageTable.builder()
                .businessId(vehicleId)
                .imageUrl(imageUrl)
                .imageCode(imageEnum.getImageType())
                .description(imageEnum.getImageName())
                .build();
    }
}
